import 'package:ac/api/ac_urls.dart';
import 'package:ac/common/ac_chat_util.dart';
import 'package:ac/data/ac_global_controller.dart';
import 'package:ac/data/ac_user_manager.dart';
import 'package:ac/route/ac_route_pages.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:rongcloud_im_wrapper_plugin/rongcloud_im_wrapper_plugin.dart';

import '../../model/ac_login_model.dart';
import 'ac_message_state.dart';

typedef OnMessage = void Function(RCIMIWMessage message);
typedef OnMessageSending = void Function(RCIMIWMessage message, int progress);

class ACConversation {
  RCIMIWConversation? conversation;
  Userinfo userinfo;

  ACConversation(this.conversation, this.userinfo);
}

class AcMessageLogic extends GetxController {
  final AcMessageState state = AcMessageState();
  late RCIMIWEngine? engine;

  List<OnMessage> onReceiveMessageListener = [];
  List<OnMessage> ooMessageAttachedListener = [];
  List<OnMessage> onMessageSentListener = [];
  List<OnMessage> onMediaMessageAttachedListener = [];
  List<OnMessageSending> onMediaMessageSendingListener = [];
  List<OnMessage> onMediaMessageDownloadedListener = [];

  @override
  void onInit() {
    // TODO: implement onInit
    super.onInit();
    _init();
    initFollowList();
  }

  void addOnReceiveMessageListener(OnMessage listener) {
    onReceiveMessageListener.add(listener);
  }

  void addOnMessageAttachedListener(OnMessage listener) {
    ooMessageAttachedListener.add(listener);
  }

  void addOnMessageSentListener(OnMessage listener) {
    onMessageSentListener.add(listener);
  }

  void addOnMediaMessageAttachedListener(OnMessage listener) {
    onMediaMessageAttachedListener.add(listener);
  }

  void addOnMediaMessageSendingListener(OnMessageSending listener) {
    onMediaMessageSendingListener.add(listener);
  }

  void addOnMediaMessageDownloadedListener(OnMessage listener) {
    onMediaMessageDownloadedListener.add(listener);
  }

  void removeOnReceiveMessageListener(OnMessage listener) {
    onReceiveMessageListener.remove(listener);
  }

  void removeOnMessageAttachedListener(OnMessage listener) {
    ooMessageAttachedListener.remove(listener);
  }

  void removeOnMessageSentListener(OnMessage listener) {
    onMessageSentListener.remove(listener);
  }

  void removeOnMediaMessageAttachedListener(OnMessage listener) {
    onMediaMessageAttachedListener.remove(listener);
  }

  void removeOnMediaMessageSendingListener(OnMessageSending listener) {
    onMediaMessageSendingListener.remove(listener);
  }

  void removeOnMediaMessageDownloadedListener(OnMessage listener) {
    onMediaMessageDownloadedListener.remove(listener);
  }

  // 删除会话
  void deleteConversation(RCIMIWConversationType type, String targetId) async {
    IRCIMIWRemoveConversationCallback? callback =
        IRCIMIWRemoveConversationCallback(
      onConversationRemoved: (int? code) {},
    );

    engine?.removeConversation(type, targetId, null, callback: callback);
    initConversationList();
  }

  Future<void> _init() async {
    var globalController = Get.find<AcGlobalController>();
    await globalController.initConfig();
    var key = globalController.rckKey.value;
    RCIMIWEngineOptions options = RCIMIWEngineOptions.create();
    engine = await RCIMIWEngine.create(key, options);
    engine?.onConnectionStatusChanged = _handleConnectionStatusChanged;
    engine?.onMessageReceived = _handleMessageReceived;
    engine?.onMessageAttached = _handleMessageAttached;
    engine?.onMessageSent = _handleMessageSent;
    engine?.onMediaMessageAttached = _handleMediaMessageAttached;
    engine?.onMediaMessageSending = _handleMediaSending;
    engine?.onMediaMessageSent = _handleMessageSent;
    engine?.onMediaMessageDownloaded = _handleMediaDownloaded;
    _connect();
  }

  void _connect() async {
    var result =
        await AcUrls.getToken.get(showLoading: false, showErrorMessage: false);
    var token = result?["data"];
    RCIMIWConnectCallback? callback = RCIMIWConnectCallback(
      onDatabaseOpened: (int? code) {
        debugPrint("onDatabaseOpened: $code");
      },
      onConnected: (int? code, String? userId) {
        initConversationList();
      },
    );
    engine?.connect(token, 15, callback: callback);
  }

  void initConversationList() async {
    IRCIMIWGetConversationsCallback? callback = IRCIMIWGetConversationsCallback(
      onSuccess: (List<RCIMIWConversation>? t) async {
        if (t == null) return;
        state.conversationList.clear();
        for (var c in t) {
          var acc = await getACConversation(c);
          if (acc != null) {
            if (state.conversationList.firstWhereOrNull((element) =>
                    element.conversation?.targetId ==
                    acc.conversation?.targetId) !=
                null) {
              state.conversationList.removeWhere((element) =>
                  element.conversation?.targetId == acc.conversation?.targetId);
            }
            state.conversationList.add(acc);
          }
        }
      },
      onError: (int? code) {
        debugPrint('getConversations error code = $code');
      },
    );

    await engine?.getConversations(
        [RCIMIWConversationType.private], null, 0, 50,
        callback: callback);
  }

  sendTextMsg(String targetId) async {
    RCIMIWTextMessage? message = await engine?.createTextMessage(
      RCIMIWConversationType.private,
      targetId,
      null,
      "hello",
    );

    RCIMIWSendMessageCallback? callback = RCIMIWSendMessageCallback(
        onMessageSaved: (RCIMIWMessage? message) {
          debugPrint('onMessageSaved: $message');
          initConversationList();
        },
        onMessageSent: (int? code, RCIMIWMessage? message) {});

    engine?.sendMessage(message as RCIMIWMessage, callback: callback);
  }

  Future<ACConversation?> getACConversation(
      RCIMIWConversation conversation) async {
    return AcChatUtil.getChatWithConversation(conversation);
  }

  void toChatPage(ACConversation conversation) {
    Get.toNamed(
      AcRouteNames.chatPage,
      arguments: {
        "conversation": conversation,
      },
    );
  }

  _handleConnectionStatusChanged(RCIMIWConnectionStatus? status) {
    debugPrint("status: $status");
  }

  _handleMessageReceived(
      RCIMIWMessage? message, int? left, bool? offline, bool? hasPackage) {
    debugPrint("message: $message, $left, $offline, $hasPackage");
    initConversationList();
    for (var listener in onReceiveMessageListener) {
      listener(message!);
    }
  }

  _handleMessageAttached(RCIMIWMessage? message) {
    debugPrint("message: $message");
    for (var listener in ooMessageAttachedListener) {
      listener(message!);
    }
  }

  _handleMessageSent(int? code, RCIMIWMessage? message) {
    debugPrint("message: $message");
    for (var listener in onMessageSentListener) {
      listener(message!);
    }
  }

  _handleMediaMessageAttached(RCIMIWMediaMessage? message) {
    for (var listener in onMediaMessageAttachedListener) {
      listener(message!);
    }
  }

  Future<void> logout() async {
    await engine?.disconnect(false);
    await engine?.destroy();
  }

  _handleMediaSending(RCIMIWMediaMessage? message, int? progress) {
    for (var listener in onMediaMessageSendingListener) {
      listener(message!, progress!);
    }
  }

  _handleMediaDownloaded(int? code, RCIMIWMediaMessage? message) {
    for (var listener in onMediaMessageDownloadedListener) {
      listener(message!);
    }
  }

  Future<void> initFollowList() async {
    var res = await AcUrls.followList.post(
      data: {
        "page": 1,
        "limit": 100,
      },
      showLoading: false,
    );
    if (res?["code"] == 0) {
      state.followList.value =
          (res["data"] as List).map((e) => Userinfo.fromJson(e)).toList();
    }
  }

  Future<void> unfollow(Userinfo userinfo) async {
    var res = await AcUrls.unFollow.post(data: {
      "followUserId": userinfo.userId,
    });
    if (res?["code"] == 0) {
      state.followList.remove(userinfo);
      AcUserManager.updateBloggerUserInfo(userinfo);
    }
  }

  void handleBlock(Userinfo userinfo) {
    state.followList.remove(userinfo);
    for (var element in state.conversationList) {
      if (element.conversation?.targetId == userinfo.userId) {
        state.conversationList.remove(element);
        engine?.removeConversation(
            RCIMIWConversationType.private, userinfo.userId!, null);
        break;
      }
    }
  }
}
